package com.captcha.utils;

import com.captcha.enums.Constants;
import com.sun.xml.internal.ws.util.UtilException;

import java.awt.*;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

/**
 * @Author: 随风飘的云
 * @Description: random随机数工具类。
 * @Date: 2022/2/24 12:08
 * @Modified By:
 */
public class RandomUtils {

    /**
     * 获取随机数生成器对象
     * ThreadLocalRandom是JDK 7之后提供并发产生随机数，能够解决多个线程发生的竞争争夺。
     * 注意：此方法返回的{@link ThreadLocalRandom}不可以在多线程环境下共享对象，否则有重复随机数问题。
     * @return
     */
    public static ThreadLocalRandom getRandom(){
        return ThreadLocalRandom.current();
    }

    /**
     * 创建{@link SecureRandom}，类提供加密的强随机数生成器 (RNG)
     * @param seed 自定义随机种子
     * @return {@link SecureRandom}
     */
    public static SecureRandom createSecureRandom(byte[] seed){
        return (null == seed) ? new SecureRandom() : new SecureRandom(seed);
    }

    /**
     * 获取SHA1PRNG的{@link SecureRandom}，类提供加密的强随机数生成器 (RNG)
     * 注意：此方法获取的是伪随机序列发生器PRNG（pseudo-random number generator）
     * @return
     */
    public static SecureRandom getSecureRandom(){
        return getSecureRandom(null);
    }

    /**
     * 获取SHA1PRNG的{@link SecureRandom}，类提供加密的强随机数生成器
     * 注意：此方法获取的是伪随机序列发生器PRNG（pseudo-random number generator）
     * @param seed 随机数种子
     * @return {@link SecureRandom}
     * @see #createSecureRandom(byte[])
     */
    public static SecureRandom getSecureRandom(byte[] seed){
        return createSecureRandom(seed);
    }

    /**
     * 获取SHA1PRNG的{@link SecureRandom}，类提供加密的强随机数生成器
     * 注意：此方法获取的是伪随机序列发生器PRNG（pseudo-random number generator）,在Linux下噪声生成时可能造成较长时间停顿。
     * @param seed 随机数种子
     * @return {@link SecureRandom}
     */
    public static SecureRandom getSHA1PRNGRandom(byte[] seed){
        SecureRandom random;
        try {
            random = SecureRandom.getInstance("SHA1PRNG");
        } catch (NoSuchAlgorithmException e){
            throw new UtilException(e);
        }
        if (seed != null){
            random.setSeed(seed);
        }
        return random;
    }

    /**
     * 获取随机数生产器
     * @param isSecure
     * @return
     */
    public static Random getRandom(boolean isSecure){
        return isSecure ? getSecureRandom() : getRandom();
    }

    /**
     * 获取随机int值，-2^31到2^31之间
     * @return
     */
    public static int randomInt(){
        return getRandom().nextInt();
    }

    /**
     * 获取指定范围内的随机数[0,limit)
     * @param limit
     * @return
     */
    public static int randomInt(int limit){
        return getRandom().nextInt(limit);
    }

    /**
     * 获得指定范围内的随机数[min,max)
     * @param min 最小值
     * @param max 最大值
     * @return
     */
    public static int randomInt(int min, int max){
        return getRandom().nextInt(min, max);
    }

    /**
     * 获取[0,1)的随机数
     * @return
     */
    public static double randomDouble(){
        return getRandom().nextDouble();
    }

    /**
     * 获取随机boolean值
     * @return
     */
    public static boolean getRandomBool() {
        return randomInt(2) == 0;
    }

    /**
     * 获取多个随机常用中文汉字
     * @param length
     * @return
     */
    public static String randomChinese(int length){
        return RandomString(Constants.MODERN_CHINESE, length);
    }

    /**
     * 随机从264个成语中获取一个
     * @return
     */
    public static String randomIdiom(){
        return Constants.CHINESE_IDIOM[randomInt(263)];
    }

    /**
     * 随机获取成语的排序
     * @return
     */
    public static int[] getRandomIdiom() {
        return Constants.IDIOM_ID[randomInt(24)];
    }

    /**
     * 获得随机long值
     * @return
     */
    public static long getRandomLong(){
        return getRandom().nextLong();
    }

    /**
     * 获取byte随机数
     * @param length byte数组的长度
     * @return
     */
    public static byte[] getRandomByte(int length){
        byte[] bytes = new byte[length];
        getRandom().nextBytes(bytes);
        return bytes;
    }

    /**
     * 获取随机颜色
     * @return
     */
    public static Color randomColor(){
        int[] color = Constants.COLORS_ID[randomInt(Constants.COLORS_ID.length)];
        return new Color(color[0], color[1], color[2]);
    }

    /**
     * 获取一个字符串，只包含数字。
     * @param length
     * @return
     */
    public static String RandomNumber(int length){
        // 去掉前导0
        String str = RandomString(Constants.BASE_NUMBER, length);
        str.replaceAll("^0+(?!$)", "");
        return str;
    }

    /**
     * 随机获取0~9的中文简体数字
     * @return
     */
    public static char RandomComplexNumber() {
        return Constants.BASE_COMPLEX_NUMBER[randomInt(10)];
    }


    /**
     * 随机获取多个0~9的中文简体数字
     * @param length
     * @return
     */
    public static String RandomComplexNumber(int length) {
        return RandomString(Constants.BASE_COMPLEX_NUMBER, length);
    }

    /**
     * 获取一个字符串，只包含字母。
     * @param length
     * @return
     */
    public static String RandomChar(int length){
        return RandomString(Constants.BASE_CHAR, length);
    }

    /**
     * 获取一个字符串，只包含字母，大写
     * @param length
     * @return
     */
    public static String RandomUpperChar(int length){
        return RandomString(Constants.BASE_UPPER_CHAR, length);
    }

    /**
     * 获取一个随机字符串（只包含数字和字符）
     * @param length
     * @return
     */
    public static String RandomString(int length){
        return RandomString(Constants.BASE_NUMBER_CHAR, length);
    }

    /**
     * 获取一个随机字符串（只包含数字和大小写字符）
     * @param length
     * @return
     */
    public static String RandomStringUpper(int length){
        return RandomString(Constants.UPPER_NUMBER_CHAR, length);
    }

    /**
     * 获取一个随机字符串
     * @param base 传入的基础字符串
     * @param length 需要的随机字符串长度
     * @return
     */
    public static String RandomString(char[] base, int length){
        // 获取当前的基础字符串的长度
        int len = base.length;
        // 判断传入字符串是否为空
        if(len == 0){
            return "";
        }
        // 创建builder，方便构造String
        final StringBuilder builder = new StringBuilder(length);
        // 判断需要的随机字符串的长度
        if(length < 1){
            length = 1;
        }
        // 以基础字符串为核心构造随机字符串
        for (int i = 0; i < length; i++) {
            int number = randomInt(len);
            builder.append(base[number]);
        }
        return builder.toString();
    }
}
